package com.bob.clan.wxconnector.util;


import com.bob.clan.wxconnector.exception.MpException;
import lombok.extern.slf4j.Slf4j;


import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;


/**
 * Created with IntelliJ IDEA.
 * User: hc.zhao
 * Date: 15-3-20
 * Time: 上午11:45
 * To change this template use File | Settings | File Templates.
 */
@Slf4j
public class HttpUtil {

    private static Map<String, String> paramMap;
    private static PoolingHttpClientConnectionManager connMgr;
    private static RequestConfig requestConfig;

    public static String reqJsonGet(String url) throws MpException {
        log.debug("---do get http---");
        CloseableHttpClient httpClient = createSSLClientDefault();
        HttpGet get = new HttpGet(url);
        CloseableHttpResponse response;
        try {
            response = httpClient.execute(get);
            HttpEntity entity = response.getEntity();
            String respStr = EntityUtils.toString(entity, "UTF-8");
            EntityUtils.consume(entity);
            log.debug("do get, respStr=" + respStr);
            if (null != respStr && !"".equals(respStr)) {
                JSONObject jret = (JSONObject) JSONObject.parse(respStr);
                if (jret.containsKey("errcode")) {
                    if (jret.get("errcode").equals("40029") || jret.get("errcode").equals("40001")) {
                        throw new MpException(MpException.TokenInvalidHit, "httputil 访问微信资源");
                    }
                }
            }
            return respStr;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            get.releaseConnection();
        }
        return "";
    }

    public static JSONObject reqJsonPost(String url, JSONObject paramJson) {
        log.debug("---do post http by paramJson---");
        JSONObject retJson = null;
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setConnectTimeout(25000);
            conn.setReadTimeout(25000);
            HttpURLConnection.setFollowRedirects(true);
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");
            conn.setRequestProperty("Referer", "https://api.weixin.qq.com/");
            conn.connect();

            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
//            out.write(new String(paramJson.toJSONString().getBytes("UTF-8"),"GB18030"));
            out.write(paramJson.toJSONString());
            out.flush();
            out.close();
            InputStream in = conn.getInputStream();
            BufferedReader read = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            StringBuffer sb = new StringBuffer();
            String valueString = null;
            while ((valueString = read.readLine()) != null) {
                sb.append(valueString);
            }
            retJson = JSONObject.parseObject(sb.toString());
            in.close();
            if (conn != null) {
                conn.disconnect();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retJson;
    }

    public static JSONObject reqJsonPost(String url, String paramJson) {
        log.debug("---do post http by paramJson---");
        JSONObject retJson = null;
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setConnectTimeout(25000);
            conn.setReadTimeout(25000);
            HttpURLConnection.setFollowRedirects(true);
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");
            conn.setRequestProperty("Referer", "https://api.weixin.qq.com/");
            conn.connect();
            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            out.write(paramJson);
            out.flush();
            out.close();
            InputStream in = conn.getInputStream();
            BufferedReader read = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            StringBuffer sb = new StringBuffer();
            String valueString = null;
            while ((valueString = read.readLine()) != null) {
                sb.append(valueString);
            }
            retJson = JSONObject.parseObject(sb.toString());
            in.close();
            if (conn != null) {
                conn.disconnect();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retJson;
    }


    public static synchronized String reqJsonPost(String url, Map curParamMap) {
        log.debug("---do post http---");
        paramMap = curParamMap;
        String retJO = reqJsonPost(url);
        paramMap = null;
        return retJO;
    }

    public static String reqJsonPost(String url) {
        log.debug("---do post http---");
        String baseUrl = getBaseUrl(url);
        String responseHtml = "{}";
        HttpClient client = HttpClients.createDefault();
        if (baseUrl.indexOf("https") == 0) {
            //client = HttpsUtil.wrapClient(client);
            client = createSSLClientDefault();
        }
        Map<String, String> map = null;
        if (paramMap == null) {
            map = getMapByUrl(url);
        } else {
            map = paramMap;
        }
        HttpPost post = new HttpPost(baseUrl);
        List<NameValuePair> parms = new ArrayList<NameValuePair>();

        Set<String> keyset = map.keySet();
        for (String key : keyset) {
            parms.add(new BasicNameValuePair(key, map.get(key)));
        }

        UrlEncodedFormEntity entity;
        try {
            entity = new UrlEncodedFormEntity(parms, "UTF-8");
            post.setEntity(entity);
            log.debug("executing request " + post.getURI());
            HttpResponse response = client.execute(post);
            HttpEntity entity2 = response.getEntity();

            responseHtml = EntityUtils.toString(entity2, "UTF-8");
            log.debug("do post, respStr=" + responseHtml);

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            client.getConnectionManager().shutdown();
        }
        return responseHtml;
    }

    private static String getBaseUrl(String url) {
        return url.substring(0, url.indexOf("?"));
    }

    private static Map<String, String> getMapByUrl(String url) {
        Map<String, String> paramMap = new HashMap<String, String>();
        String kvstr = url.substring(url.indexOf("?") + 1);
        String[] kvArr = kvstr.split("&");
        for (int i = 0; i < kvArr.length; i++) {
            String kv = kvArr[i];
            String[] kvmap = kv.split("=");
            paramMap.put(kvmap[0], kvmap[1]);
        }
        return paramMap;
    }


    private static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();
    }


    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private synchronized static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {

                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }

                @Override
                public void verify(String host, SSLSocket ssl) throws IOException {
                }

                @Override
                public void verify(String host, X509Certificate cert) throws SSLException {
                }

                @Override
                public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
                }
            });
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return sslsf;
    }

    /**
     * 发送 SSL POST 请求（HTTPS），JSON形式
     *
     * @param url       API接口URL
     * @param paramJson 请求数据
     * @return
     */
    public synchronized static JSONObject doPostSSL(String url, JSONObject paramJson) {
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String httpStr = null;

        try {
            httpPost.setConfig(requestConfig);
            StringEntity stringEntity = new StringEntity(paramJson.toJSONString(), "UTF-8");//解决中文乱码问题
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            log.debug("Return status code =" + response.getStatusLine().getStatusCode());
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
//                throw new RemoteServiceException(url, response.getStatusLine().getStatusCode(), null);
            }
            HttpEntity entity = response.getEntity();
            if (entity == null) {
                return null;
            }
            httpStr = EntityUtils.toString(entity, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return JSONObject.parseObject(httpStr);
    }
}
